package com.pro.core.util;

import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.ui.ExtendedModelMap;
import org.springframework.web.multipart.support.AbstractMultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequestWrapper;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

public class AopUtils {

    private static ExpressionParser parser;
    /**
     * 获取被拦截方法对象
     *
     * MethodSignature.getMethod() 获取的是顶层接口或者父类的方法对象 而缓存的注解在实现类的方法上
     * 所以应该使用反射获取当前对象的方法对象
     */
    public static Method getMethod(ProceedingJoinPoint pjp) {
        // 获取参数的类型
        Class<?>[] parameterTypes = ((MethodSignature)pjp.getSignature()).getMethod().getParameterTypes();
        //此方法当参数传递null时会报错,故而改为采用上述方式
        // Object[] args = pjp.getArgs();
        // Class[] argTypes = new Class[pjp.getArgs().length];
        // for (int i = 0; i < args.length; i++) {
        // if (args[i]!=null) {
        // argTypes[i] = args[i].getClass();
        // }
        // }
        Method method = null;
        try {
            method = pjp.getTarget().getClass().getMethod(pjp.getSignature().getName(), parameterTypes);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        }
        return method;
    }
    /**
     * 通过spring spel解析参数获取redis缓存key
     *
     * @param keys
     *            缓存keys
     * @param paramNames
     *            参数名
     * @param args
     *            参数列表
     * @return
     */
    public static String parseKeyByParam(String keys, String[] paramNames, Object[] args) {
        if (StringUtils.isBlank(keys)) {
            return "";
        }
        ExpressionParser parser = getParser();
        StandardEvaluationContext context = new StandardEvaluationContext();
        // 把方法参数放入SPEL上下文中
        for (int i = 0; i < paramNames.length; i++) {
            context.setVariable(paramNames[i], args[i]);
        }
        // 获取参数key
        StringBuffer sb = new StringBuffer();
        // for (int i = 0; i < keys.length; i++) {
        sb.append(parser.parseExpression(keys).getValue(context, String.class));
        // }
        return sb.toString();
    }

    /**
     * 获取参数名列表
     *
     * @param method
     * @return
     */
    public static String[] getMethodParamNames(Method method) {
        // 获取被拦截方法参数名列表(使用Spring支持类库)
        LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();
        String[] paraNameArr = u.getParameterNames(method);
        return paraNameArr;
    }

    /**
     * 获取缓存主键
     * @param jp
     * @param clazz
     * @return
     * @throws SecurityException
     * @throws NoSuchFieldException
     */
//	public static <T extends Annotation> String[] getCachedKey(T t,String[] paramNames, Class<T> clazz) throws NoSuchFieldException, SecurityException {
////		Method method = getMethod(jp);
////		T t = getMethodAnnotation(method, clazz);
//		// String fieldKey = null;
//		// if (cache.isParam()) {
//		String fieldKey = parseKeyByParam(ReflectionUtil.getField(t.getClass().getField("cachekey"), t).toString(), paramNames, jp.getArgs());
//		// }
//		return fieldKey.split(",");
//	}

    /**
     * 获取方法注解
     * @param method
     * @param clazz 注解类型
     * @return
     */
    public static <T extends Annotation> T getMethodAnnotation(Method method, Class<T> clazz){
        T t = method.getAnnotation(clazz);
        return t;
    }
    /**
     * 获取redis缓存key通过集合参数
     *
     * @param keys
     *            缓存keys
     * @param returnObj
     *            参数列表
     * @return
     */
    private String parseKeyByReturn(String keys, Object returnObj) {
        ExpressionParser parser = getParser();
        StandardEvaluationContext context = new StandardEvaluationContext();
        // 把方法参数放入SPEL上下文中
        context.setVariable("obj", returnObj);
        // 获取参数key
        StringBuffer sb = new StringBuffer();
        sb.append(parser.parseExpression(keys).getValue(context, String.class));
        return sb.toString();
    }
    /**
     * 使用SPEL进行key的解析
     *
     * @return
     */
    public synchronized static ExpressionParser getParser() {
        if (parser == null) {
            parser = new SpelExpressionParser();
        }
        return parser;
    }
    /**
     * 执行切入点方法
     * @param jp
     * @param params 方法参数
     * @return
     */
    public static Object executeJoinPointMethod(ProceedingJoinPoint jp,Object[] params){
        Object obj = null;
        try {
            if (params==null||params.length==0) {
                obj = jp.proceed();
            }else{
                obj = jp.proceed(params);
            }
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return obj;
    }

    public static String getRequestString(JoinPoint joinPoint) {
        Object[] args = joinPoint.getArgs();
        StringBuffer buffer = new StringBuffer("{");
        try {
            if (null != args) {
                for (int i=0, size = args.length; i < size; i++) {
                    if (null == args[i] || args[i] instanceof ExtendedModelMap || args[i] instanceof HttpServletRequestWrapper
                            || args[i] instanceof AbstractMultipartHttpServletRequest
                            || args[i].getClass().getName().startsWith("org.apache.catalina.connector.ResponseFacade")
                            || args[i].getClass().getName().startsWith("[Lorg.springframework.web.multipart.MultipartFile")) continue;
                    buffer.append(JSON.toJSONString(args[i]));
                    if (i != size - 1) buffer.append(",");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        buffer.append("}");
        return buffer.toString();
    }
}
